home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / bit / src / scratch.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  18KB  |  725 lines

  1. /*
  2.  * $Id: scratch.c,v 0.91 1994/02/20 00:52:51 zhao Pre-Release $
  3.  *
  4.  *. This file is part of BIT shareware package. After the two weeks of
  5.  *  free evaluation period, you are encouraged (required) to register
  6.  *  your copy for a small registration fee, which is $35 for personal use
  7.  *  and $50 for commercial, government and institutional use.
  8.  *
  9.  *  Copyright(c) 1993, 1994 by T.C. Zhao.
  10.  *  All rights reserved.
  11.  *
  12.  *  Permission to use, copy, and distribute this software in its entirety
  13.  *  for non-commercial purposes is hereby granted, provided that the
  14.  *  above shareware and copyright notices and this permission notice
  15.  *  appear in all copies and their documentation.
  16.  *
  17.  *  This software may be modified for your own use, but modified versions
  18.  *  may not be distributed without prior consent of the author.
  19.  *
  20.  *  This software is provided "as is" without expressed or implied
  21.  *  warranty of any kind.
  22.  *
  23.  *.
  24.  *
  25.  * A. Scratch files for possible backing store. Neither portable nor
  26.  *    efficient. Probably should make it portable.
  27.  *
  28.  * B. Hacks to read compressed and not-directly-supported formats
  29.  *
  30.  */
  31. #if !defined(lint) && defined(F_ID)
  32. char *id_sh = "$Id: scratch.c,v 0.91 1994/02/20 00:52:51 zhao Pre-Release $";
  33. #endif
  34.  
  35. #include "bit.h"
  36. #include "dmalloc.h"
  37.  
  38. /******************************************************************
  39.  * Handle TMP file formats
  40.  *
  41.  * For the specification of the BIT1.0 format, See files in ../docs
  42.  * directory.
  43.  **************************************************************{*/
  44.  
  45. /************************* Limits and defines ********************/
  46.  
  47. #define TMPSIG    "BIT1.0"    /* signature  */
  48. #define TMPSIGL   (sizeof(TMPSIG)-1)    /* its length */
  49.  
  50. /*********************** Local variables ************************/
  51.  
  52. static int pc_resolution, channel, compression;
  53.  
  54. /**************************************************************/
  55. int
  56. TMP_desc(IPTR im)
  57. {
  58.     char buf[10];
  59.     FILE *fp = im->fp;
  60.  
  61.     fread(buf, 1, TMPSIGL, fp);    /* ignore signature */
  62.  
  63.     im->w = get2LSBF(fp);
  64.     im->h = get2LSBF(fp);
  65.     pc_resolution = getc(fp);
  66.     channel = getc(fp);
  67.     compression = getc(fp);
  68.  
  69.     M_info("TMP_desc", "%s: Res=%d Channel=%d Comp=%d",
  70.        pc_resolution, channel, compression);
  71.  
  72.     if (pc_resolution < 0 || pc_resolution > 2)
  73.       {
  74.       Bark("TMP_desc", "Bad PC resolution: %d", pc_resolution);
  75.       return -1;
  76.       }
  77.  
  78.     if (channel < 0)
  79.       {
  80.       Bark("TMP_desc", "Bad color components: %d", channel);
  81.       return -1;
  82.       }
  83.  
  84.     if (channel > 4 && !(channel == 5 && pc_resolution == 1))
  85.       {
  86.       Bark("TMP_desc", "Bad color components: %d", channel);
  87.       return -1;
  88.       }
  89.  
  90.     if (channel == 0 || channel == 2)
  91.       {                /* colormap */
  92.       int ncolors = get2LSBF(fp);
  93.       if (ncolors < 0)
  94.         {
  95.         Bark("TMP_desc", "Bad colormap entries: %d", ncolors);
  96.         return -1;
  97.         }
  98.       im->colors = im->cmap->colors = ncolors;
  99.       if (pc_resolution == sizeof(pc_t))
  100.         {
  101.         fread(im->cmap->ct[0], sizeof(pc_t), ncolors, fp);
  102.         fread(im->cmap->ct[1], sizeof(pc_t), ncolors, fp);
  103.         fread(im->cmap->ct[2], sizeof(pc_t), ncolors, fp);
  104.         }
  105.       else
  106.         {            /* to be implemented */
  107.         Bark("TMP_desc", "highier resolution not supported yet");
  108.         return -1;
  109.         }
  110.       im->type = channel ? T_GMAP : T_CMAP;
  111.       }
  112.     else
  113.       {                /* truecolor */
  114.       im->type = channel == 1 ? T_GRAY : T_RGBA;
  115.       }
  116.     return 0;
  117. }
  118.  
  119. /*****************************************************************/
  120.  
  121. int
  122. TMP_load(IPTR im)
  123. {
  124.     FILE *fp = im->fp;
  125.     size_t total = im->w * im->h;
  126.     long ok = total;
  127.  
  128.     show_busy("Loading ...");
  129.     im->xi = get2LSBF(fp);
  130.     im->yi = get2LSBF(fp);
  131.     im->xf = im->xi + im->w - 1;
  132.     im->yf = im->yi + im->h - 1;
  133.  
  134.     if (compression)
  135.       {
  136.       to_be_written("TMP_load compression");
  137.       return -1;
  138.       }
  139.     if (IS_CI(im))
  140.       {                /* colormap */
  141.       ok = fread(im->raster, im->esize, total, fp);
  142.       }
  143.     else if (channel != 5)
  144.       {                /* non-packed */
  145.       int r, g, b, a;
  146.       rgba_t *ras = im->raster, *rs;
  147.  
  148.       /* if we get here, we know resolution must be 1 */
  149.  
  150. #if 0                /* forcing use getc */
  151.       int (*readit) (FILE *);
  152.       readit = (resolution == 1) ? fgetc : get2LSBF;
  153. #else
  154.  
  155. #define readit getc
  156. #endif
  157.  
  158.  
  159.       if (channel == 1)
  160.         {
  161.         for (rs = ras + total; ras < rs; ras++)
  162.           {
  163.               r = readit(fp);
  164.               *ras = Pack(r, r, r);
  165.           }
  166.         }
  167.       else if (channel == 3)
  168.         {
  169.         for (rs = ras + total; ras < rs; ras++)
  170.           {
  171.               r = readit(fp);
  172.               g = readit(fp);
  173.               b = readit(fp);
  174.               *ras = Pack(r, g, b);
  175.           }
  176.         }
  177.       else if (channel == 4)
  178.         {
  179.         for (rs = ras + total; ras < rs; ras++)
  180.           {
  181.               r = readit(fp);
  182.               g = readit(fp);
  183.               b = readit(fp);
  184.               a = readit(fp);
  185.               *ras = Pack4(r, g, b, a);
  186.           }
  187.         }
  188.       }
  189.     else
  190.       {                /* packed already */
  191.       ok = fread(im->raster, sizeof(rgba_t), total, fp);
  192.       }
  193.     end_busy();
  194.     return (ok > total / 2) ? im->h : -1;
  195. }
  196.  
  197. /***************** Writing Routines *****************************/
  198. static int packedpix = 1;
  199.  
  200. /* ARGSUSED */
  201. const char *
  202. TMP_wdefault(const IPTR im)
  203. {
  204.     return packedpix ? "Packed" : "Non-packed";
  205. }
  206.  
  207. /* ARGSUSED */
  208. int
  209. TMPdump_init(IPTR im)
  210. {
  211.     return (packedpix = !packedpix);
  212. }
  213.  
  214. int
  215. TMP_dump(IPTR im)
  216. {
  217.     size_t total = im->w * im->h;
  218.     FILE *fp = im->fp;
  219.  
  220.     show_busy("Writing ...");
  221.  
  222.     if (Badfwrite(TMPSIG, 1, TMPSIGL, fp))
  223.     return -1;
  224.  
  225.     put2LSBF(im->w, fp);
  226.     put2LSBF(im->h, fp);
  227.     putc(sizeof(pc_t), fp);
  228.  
  229.     /* always write channel 5 */
  230.     channel = IS_CI(im) ? (IS_GRAY(im) ? 2 : 0) :
  231.     (IS_GRAY(im) ? 1 : (packedpix ? 5 : 3));
  232.  
  233.     putc(channel, fp);
  234.     putc(0, fp);        /* compression */
  235.  
  236.  
  237.     if (IS_CI(im))
  238.       {
  239.       int ncolors = im->cmap->colors;
  240.       put2LSBF(ncolors, fp);
  241.       fwrite(im->cmap->ct[0], 1, ncolors, fp);
  242.       fwrite(im->cmap->ct[1], 1, ncolors, fp);
  243.       fwrite(im->cmap->ct[2], 1, ncolors, fp);
  244.       }
  245.     put2LSBF(im->xi, fp);
  246.     put2LSBF(im->yi, fp);
  247.  
  248.     if (IS_CI(im))
  249.       {
  250.       fwrite(im->raster, sizeof(ci_t), im->w * im->h, fp);
  251.       }
  252.     else if (channel == 1)
  253.       {                /* grayscale */
  254.       register rgba_t *ras = im->raster, *rs;
  255.       for (rs = ras + total; ras < rs; ras++)
  256.         {
  257.         putc((*ras & 0xff), fp);
  258.         }
  259.       }
  260.     else if (channel == 3)
  261.       {                /* seperate RGB */
  262.       register rgba_t *ras = im->raster, *rs;
  263.       register int r, g, b;
  264.       for (rs = ras + total; ras < rs; ras++)
  265.         {
  266.         Unpack(*ras, r, g, b);
  267.         putc(r, fp);
  268.         putc(g, fp);
  269.         putc(b, fp);
  270.         }
  271.       }
  272.     else
  273.       {
  274.       fwrite(im->raster, sizeof(rgba_t), total, fp);
  275.       }
  276.     end_busy();
  277.     return fflush(fp);
  278. }
  279.  
  280. /***********************************************************************
  281.  * END OF TMP FILE
  282.  ******************************************************************}*/
  283.  
  284.  
  285. /**************************************************************************
  286.  *
  287.  * FORMATS that rely on external program to convert to one of the known
  288.  * formats. Can't use popen(.....) because we need to guarantee seek-ability
  289.  *
  290.  **************************************************************************/
  291.  
  292. #include <stdlib.h>        /* for system */
  293. static const char *pref = ".BIT";    /* tmp file prefix */
  294. extern IMG_IO img_io[];
  295.  
  296. /********************************************************************
  297.  * the driver routine that uncompress/converts or whatever to read
  298.  * an images description. It takes command names, options and whole
  299.  * bunch of things to do the magic
  300.  ********************************************************************/
  301. static int
  302. fake_desc(IPTR im, const char *cmds[], const char *func, const char *prgs)
  303. {
  304.     char cmd[1024];
  305.     const char *const *q = cmds;
  306.     int found[5], i, status, total;
  307.     char *tmp_file;
  308.     IMG_IO *p;
  309.     FILE *fp;
  310.  
  311.     /* get a tmp file to hold the output */
  312.     if (!(tmp_file = get_tmpf(pref)))
  313.       {
  314.       Bark(func, "Unable to get tmpfile");
  315.       return -1;
  316.       }
  317.  
  318.     update_filename(im->ifile);
  319.     update_format_info(im);
  320.  
  321.     /* now try all given conversion commands.  */
  322.     show_busy(prgs);
  323.     do
  324.       {
  325.       sprintf(cmd, *q, im->ifile, tmp_file);
  326.       status = system(cmd);
  327.       }
  328.     while (status && *++q);
  329.     end_busy();
  330.  
  331.     if (status)            /* did not succeed */
  332.       {
  333.       Bark(func, "Bad command");
  334.       del_tmpf(tmp_file);
  335.       return -1;
  336.       }
  337.  
  338.     /*
  339.      * conversion is successful. Try to read it. Can't simply use open_image
  340.      * to do it because of bad recursion would occur
  341.      */
  342.     if (!(fp = fopen(tmp_file, "r")))
  343.       {
  344.       del_tmpf(tmp_file);
  345.       return -1;
  346.       }
  347.  
  348.     /* see if processed file is one of the formats we can handle */
  349.     if ((total = check_signature(fp, found, tmp_file)) <= 0)
  350.       {
  351.       del_tmpf(tmp_file);
  352.       return -1;
  353.       }
  354.  
  355.     /*
  356.      * so far so good. Do all signature matches until we get a good
  357.      * description. However, before we hand over the stuff to get_desc, need
  358.      * to change the filename to the real file because canned library might
  359.      * ignore im->fp and want to open file and do its things ...
  360.      */
  361.  
  362.     strcpy(cmd, im->ifile);
  363.     strcpy(im->ifile, tmp_file);
  364.     im->fp = fp;
  365.  
  366.     i = 0;
  367.     do
  368.       {
  369.       rewind(im->fp);
  370.       im->io = (p = img_io + found[i]);
  371.       im->t2b = p->t2b;
  372.       im->type = p->type;
  373.       if (!im->io->display)
  374.           im->io->display = Generic_display;
  375.       status = im->io->desc(im);
  376.       }
  377.     while (++i < total && status < 0);
  378.  
  379.     /* now we can safely delete the file regardless status */
  380.     del_tmpf(tmp_file);
  381.  
  382.     strcpy(im->ifile, cmd);
  383.     update_filename(im->ifile);
  384.     return status;
  385. }
  386.  
  387. /**********************************************************************
  388.  * The writing routine. All depends on structure FakeDump. The format
  389.  * string should be a command name, and four string producers to accept
  390.  * option, infile, outfile and option2, e.g., "pnmtotiff %s %s > %s %s" is
  391.  * an acceptable one.
  392.  **********************************************************************/
  393. typedef struct
  394. {
  395.     const char *cmd;        /* shell command to do it */
  396.     char *keys[4];        /* formats cmd accepts    */
  397.     int optlast;        /* for totiff. Weird stuff */
  398. }
  399. FakeDump;
  400.  
  401. /**********************************************************
  402.  * The driver
  403.  *********************************************************/
  404. static int
  405. fake_dump(IPTR im, FakeDump * fake, const char *opt1, const char *opt2,
  406.       const char *func, const char *prgs)
  407. {
  408.     int in, err;
  409.     FakeDump *f = fake;
  410.     char cmd[MAXDLEN + MAXFLEN], sf[MAXDLEN + MAXFLEN];
  411.     char *tmpf;
  412.     const char *o1 = opt1 ? opt1 : "", *o2 = opt2 ? opt2 : "";
  413.  
  414.  
  415.     if (!(tmpf = get_tmpf(pref)))
  416.       {
  417.       Bark(func, "Unable to get tmpfile");
  418.       return -1;
  419.       }
  420.  
  421.     /*
  422.      * again, need to save filenames. Some formats do  its own things with
  423.      * file names ....
  424.      */
  425.  
  426.     strcpy(sf, im->ofile);
  427.     strcpy(im->ofile, tmpf);
  428.     do
  429.       {
  430.       /*
  431.        * if the writing routine takes multiple formats, always choose the
  432.        * format that is closest to current image
  433.        */
  434.  
  435.       err = (in = best_format(im, f->keys)) < 0;
  436.  
  437.       /*
  438.        * if the format needed and the best format is not the same,
  439.        * convert to needed
  440.        */
  441.  
  442.       err = err || (img_io[in].type != T_FLEX &&
  443.             img_io[in].type != im->type &&
  444.             img_convert_type(im, img_io[in].type));
  445.  
  446.       /* write current image to disk in proper format */
  447.       err = err || !(im->fp = fopen(tmpf, "w"));
  448.       err = err || (img_io[in].dump(im) < 0);
  449.       close_image(im);
  450.  
  451.       /* generate the necassary shell command to do the job */
  452.  
  453.       if (f->optlast)
  454.           sprintf(cmd, f->cmd, "", tmpf, sf, o2);
  455.       else
  456.           sprintf(cmd, f->cmd, o1, tmpf, sf, "");
  457.  
  458.       /* do it */
  459.       M_info("Executing", cmd);
  460.       show_busy(prgs);
  461.       err = err || system(cmd);
  462.       }
  463.     while (++f && f->cmd && err);
  464.     del_tmpf(tmpf);
  465.     strcpy(im->ofile, sf);
  466.     end_busy();
  467.     return err;
  468. }
  469.  
  470. /****************************************************************
  471.  * Compressed file hack. No much to do
  472.  ****************************************************************/
  473. #ifndef NO_COMPRESS
  474. int
  475. Compress_desc(IPTR im)
  476. {
  477.     static const char *cmds[] =
  478.     {
  479.     "zcat %s > %s", 0
  480.     };
  481.     int status;
  482.     static char newinfo[128];
  483.  
  484.     strcpy(newinfo, im->io->info);
  485.     status = fake_desc(im, cmds, "CompressDesc", "Uncompressing ...");
  486.     strcat(newinfo, im->io->key);
  487.     im->info = newinfo;
  488.     return status;
  489. }
  490.  
  491. /***************************************************************
  492.  * after description, flow should've been directed to the true
  493.  * format reader via io->load, should not be here. If it reaches,
  494.  * something is very wrong
  495.  **************************************************************/
  496. /* ARGSUSED */
  497. int
  498. Compress_load(IPTR im)
  499. {
  500.     Bark("CompressLoad", "Should be be here");
  501.     return -1;
  502. }
  503. #endif /* !NO_COMPRESS */
  504.  
  505. /****************************************************************
  506.  * TIFF file support hack. Someday, I will make tiff a first
  507.  * class citizen.
  508.  *****************************************************************/
  509. #ifndef NO_TIFF
  510.  
  511. /************************************************************
  512.  * The  description routine. Again, no much to do, just call
  513.  * call fake_desc and done with it
  514.  ***********************************************************/
  515. int
  516. TIFF_desc(IPTR im)
  517. {
  518.     static const char *cmds[] =
  519.     {
  520.     "fromtiff %s %s",
  521.     "tifftopnm %s > %s",
  522.     0
  523.     };
  524.     int status;
  525.     const char *oldkey = im->io->key, *oldinfo = im->io->info;
  526.  
  527.     /*
  528.      * must save old io->key and io->info because fake_desc will replace this
  529.      * with whatever it read, e.g., IRIS RGB, we certainly don't want to
  530.      * reading a tiff file while reporting we have read an IRIS RGB
  531.      */
  532.  
  533.     status = fake_desc(im, cmds, "TIFF_Desc", "Reading ...");
  534.  
  535.     /* cheat again to get the reporting right. Two wrongs make a right! */
  536.     im->key = oldkey;
  537.     im->info = oldinfo;
  538.     return status;
  539. }
  540.  
  541. /***************************************************************
  542.  * After description, flow should've been directed to the
  543.  * true loader via io->load. Should not be here
  544.  ***************************************************************/
  545. /* ARGSUSED */
  546. int
  547. TIFF_load(IPTR im)
  548. {
  549.     Bark("TIFF_Load", "Should be be here");
  550.     return -1;
  551. }
  552.  
  553. static int tifflzw;
  554. /* ARGSUSED */
  555. int
  556. TIFF_dumpinit(IPTR im)
  557. {
  558.     tifflzw = !tifflzw;
  559.     return 0;
  560. }
  561.  
  562. /* ARGSUSED */
  563. const char *
  564. TIFF_wdefault(const IPTR im)
  565. {
  566.     return tifflzw ? "Compress" : "No Compress";
  567. }
  568.  
  569. /*********************************************************
  570.  * write a tiff file either thru totiff or pnmtotiff
  571.  *********************************************************/
  572. int
  573. TIFF_dump(IPTR im)
  574. {
  575.     static FakeDump tiffdump[] =
  576.     {
  577.     /* totiff routiens */
  578.     {"totiff %s %s %s %s",    /* command line                 */
  579.      {"iris", 0},        /* accepted formtats            */
  580.      1            /* if option goes last (wierd)  */
  581.     },
  582.  
  583.     /* PBMPlus routines */
  584.     {"pnmtotiff %s %s > %s %s",
  585.      {"ppm", "pgm", "pbm", 0},
  586.      0
  587.     },
  588.  
  589.     /* sentinel */
  590.     {0}
  591.     };
  592.  
  593.     return fake_dump(im, tiffdump, tifflzw ? "-lzw" : "-none",
  594.              tifflzw ? "-c" : 0, "TIFFDump", "PleaseWait ...");
  595. }
  596.  
  597. #endif /* ! NO_TIFF */
  598.  
  599. /** routines for developing  bit *********/
  600.  
  601. #ifdef DEVELOP_BIT
  602.  
  603. /***************************************************************
  604.  * Generate a GL cursor bitmap (16x16 mono only)
  605.  ***************************************************************/
  606. int
  607. CUR_dump(IPTR im)
  608. {
  609.     unsigned short ch[17];
  610.     unsigned short *cur = ch;
  611.     bw_t *bw;
  612.     char vname[512], *t;
  613.     FILE *fp = im->fp;
  614.     int i, j, k;
  615.  
  616.     if (im->w != 16 || im->h != 16)
  617.       {
  618.       Bark("GLCurDef", "Bad bitmap");
  619.       return -1;
  620.       }
  621.  
  622.     strcpy(vname, im->ofile);
  623.  
  624.     /* zap the extension if any */
  625.     if ((t = strchr(vname, '.')))
  626.     *t = '\0';
  627.  
  628.     for (i = 0; i < im->h; i++)
  629.       {
  630.       bw = ((bw_t **) im->mraster)[i];
  631.       for (*cur = 0, j = 0, k = 15; j < 16; j++, k--, bw++)
  632.           *cur |= (*bw != 0) << k;
  633.       cur++;
  634.       }
  635.  
  636.     /** write it */
  637.     fprintf(fp, "static unsigned short %s[] =\n {", vname);    /* } VI */
  638.     for (cur = ch, i = 0; i < 16; i += 8)
  639.       {
  640.       fprintf(fp, "%c\n    0x%04x, ", i == 0 ? ' ' : ',', *cur++);
  641.       fprintf(fp, "0x%04x, ", *cur++);
  642.       fprintf(fp, "0x%04x, ", *cur++);
  643.       fprintf(fp, "0x%04x, ", *cur++);
  644.       fprintf(fp, "0x%04x, ", *cur++);
  645.       fprintf(fp, "0x%04x, ", *cur++);
  646.       fprintf(fp, "0x%04x, ", *cur++);
  647.       fprintf(fp, "0x%04x", *cur++);
  648.       }                /* { *VI */
  649.  
  650.     fputs("\n };\n", fp);
  651.     return fflush(fp);
  652. }
  653.  
  654. int
  655. CUR_desc(IPTR im)
  656. {
  657.     return -1;
  658. }
  659.  
  660. /*******************************************************************
  661.  * Write GL Patterns from a bitmap. Pattern is 32x32 bits packed
  662.  * into 2 * 32 shorts
  663.  *******************************************************************/
  664. int
  665. PAT_dump(IPTR im)
  666. {
  667.     unsigned short ph[65], *pat;
  668.     bw_t *bw;
  669.     FILE *fp = im->fp;
  670.     int i, j, k;
  671.     char vname[512], *t;
  672.  
  673.     if (im->w != 32 || im->h != 32)
  674.       {
  675.       Bark("GLPatternWrite", "Bad input bitmap");
  676.       return -1;
  677.       }
  678.  
  679.     strcpy(vname, im->ofile);
  680.  
  681.     /* zap the extension if any */
  682.     if ((t = strchr(vname, '.')))
  683.     *t = '\0';
  684.  
  685.     pat = ph;
  686.     /* covert to GL patterns */
  687.     for (j = 0; j < im->h; j++)
  688.       {
  689.       bw = ((bw_t **) im->mraster)[j];
  690.  
  691.       for (*pat = 0, k = 15, i = 0; i < 16; k--, i++, bw++)
  692.           *pat |= (*bw != 0) << k;
  693.       pat++;
  694.  
  695.       for (*pat = 0, k = 15, i = 0; i < 16; k--, i++, bw++)
  696.           *pat |= (*bw != 0) << k;
  697.       pat++;
  698.       }
  699.  
  700.     /** write it */
  701.     fprintf(fp, "static unsigned short %s[] =\n {", vname);    /* } VI */
  702.     for (pat = ph, i = 0; i < 64; i += 8)
  703.       {
  704.       fprintf(fp, "%c\n    0x%04x, ", i == 0 ? ' ' : ',', *pat++);
  705.       fprintf(fp, "0x%04x, ", *pat++);
  706.       fprintf(fp, "0x%04x, ", *pat++);
  707.       fprintf(fp, "0x%04x, ", *pat++);
  708.       fprintf(fp, "0x%04x, ", *pat++);
  709.       fprintf(fp, "0x%04x, ", *pat++);
  710.       fprintf(fp, "0x%04x, ", *pat++);
  711.       fprintf(fp, "0x%04x", *pat++);
  712.       }                /* { *VI */
  713.  
  714.     fputs("\n };\n", fp);
  715.     return fflush(fp);
  716. }
  717.  
  718. int
  719. PAT_desc(IPTR im)
  720. {
  721.     return -1;
  722. }
  723.  
  724. #endif /* DEVELOP */
  725.